import path from 'path';
import { IJsonDB } from '../interfaces/IJsonDB';
import { DatabaseConfig, TableConfig, TransactionConfig, OperationResult, QueryCondition, IEncryptor } from '../types';
import { FileSystem } from '../utils/fileSystem';
import { Transaction } from './Transaction';
import { JsonTable } from './Table';

/**
 * 数据库核心类
 */
export class JsonDB implements IJsonDB {
    /** 数据库配置 */
    private readonly config: DatabaseConfig;

    /** 数据库路径 */
    private readonly dbPath: string;

    /** 表路径 */
    private readonly tablesPath: string;

    /** 索引文件路径 */
    private readonly indexFile: string;

    /** 加密器 */
    private readonly encryptor?: IEncryptor;

    /** 表集合 Map<表名, 表配置> */
    private tables: Map<string, TableConfig>;

    /** 表实例集合 Map<表名, 表实例> */
    private tableInstances: Map<string, JsonTable>;

    /** 活动事务集合 Map<事务ID, 事务实例> */
    private transactions: Map<string, Transaction>;

    /** 是否已初始化 */
    private initialized: boolean;

    /**
     * 构造函数
     * @param config 数据库配置
     */
    constructor(config: DatabaseConfig) {
        this.config = config;
        this.dbPath = path.resolve(config.path, config.name);
        this.tablesPath = path.join(this.dbPath, 'tables');
        this.indexFile = path.join(this.dbPath, 'db.index');
        this.encryptor = config.encryptor;
        this.tables = new Map();
        this.tableInstances = new Map();
        this.transactions = new Map();
        this.initialized = false;
    }

    /**
     * 初始化数据库
     */
    private async initialize(): Promise<void> {
        if (this.initialized) return;

        await FileSystem.ensureDir(this.dbPath);
        await FileSystem.ensureDir(this.tablesPath);

        // 读取数据库索引文件
        if (await FileSystem.exists(this.indexFile)) {
            const index = await FileSystem.readJson<{ tables: TableConfig[] }>(this.indexFile, this.encryptor);
            index.tables.forEach(table => {
                this.tables.set(table.name, table);
                this.tableInstances.set(table.name, new JsonTable(table, this.dbPath, this.encryptor))
            });
        } else {
            // 创建新的索引文件
            await FileSystem.writeJson(this.indexFile, { tables: [] }, this.encryptor);
        }

        this.initialized = true;
    }

    /**
     * 获取数据库配置
     */
    getConfig(): DatabaseConfig {
        return { ...this.config };
    }

    /**
     * 创建数据表
     * @param config 表配置
     */
    async createTable(config: TableConfig): Promise<OperationResult> {
        try {
            await this.initialize();

            if (this.tables.has(config.name)) {
                return {
                    success: true,
                    data: this.tables.get(config.name),
                }
            }

            // 创建表实例
            const table = new JsonTable(config, this.dbPath, this.encryptor);
            this.tableInstances.set(config.name, table);

            // 创建表文件
            const tablePath = path.join(this.tablesPath, `${config.name}.json`);
            await FileSystem.writeJson(tablePath, [], this.encryptor);

            // 更新索引
            this.tables.set(config.name, config);
            await this.updateIndex();

            return {
                success: true,
                data: config
            };
        } catch (error) {
            return {
                success: false,
                error: (error as Error).message
            };
        }
    }

    /**
     * 获取数据表
     * @param tableName 表名
     */
    table(tableName: string): JsonTable | undefined {
        return this.tableInstances.get(tableName);
    }

    /**
     * 删除数据表
     * @param tableName 表名
     */
    async dropTable(tableName: string): Promise<OperationResult> {
        try {
            await this.initialize();

            if (!this.tables.has(tableName)) {
                return {
                    success: false,
                    error: `Table ${tableName} does not exist`
                };
            }

            // 删除表实例
            this.tableInstances.delete(tableName);

            // 删除表文件
            const tablePath = path.join(this.tablesPath, `${tableName}.json`);
            await FileSystem.removeFile(tablePath);

            // 更新索引
            this.tables.delete(tableName);
            await this.updateIndex();

            return {
                success: true
            };
        } catch (error) {
            return {
                success: false,
                error: (error as Error).message
            };
        }
    }

    /**
     * 更新索引文件
     */
    private async updateIndex(): Promise<void> {
        const tables = Array.from(this.tables.values());
        await FileSystem.writeJson(this.indexFile, { tables }, this.encryptor);
    }

    /**
     * 开始事务
     * @param config 事务配置
     */
    async beginTransaction(config?: TransactionConfig): Promise<OperationResult> {
        try {
            await this.initialize();

            const transactionId = config?.id || `txn_${Date.now()}`;
            if (this.transactions.has(transactionId)) {
                return {
                    success: false,
                    error: `Transaction ${transactionId} already exists`
                };
            }

            const transaction = new Transaction(
                { id: transactionId, timeout: config?.timeout },
                this.dbPath
            );

            await transaction.begin();
            this.transactions.set(transactionId, transaction);

            return {
                success: true,
                data: { transactionId }
            };
        } catch (error) {
            return {
                success: false,
                error: (error as Error).message
            };
        }
    }

    /**
     * 提交事务
     * @param transactionId 事务ID
     */
    async commitTransaction(transactionId: string): Promise<OperationResult> {
        try {
            const transaction = this.transactions.get(transactionId);
            if (!transaction) {
                return {
                    success: false,
                    error: `Transaction ${transactionId} not found`
                };
            }

            await transaction.commit();
            this.transactions.delete(transactionId);

            return {
                success: true
            };
        } catch (error) {
            return {
                success: false,
                error: (error as Error).message
            };
        }
    }

    /**
     * 回滚事务
     * @param transactionId 事务ID
     */
    async rollbackTransaction(transactionId: string): Promise<OperationResult> {
        try {
            const transaction = this.transactions.get(transactionId);
            if (!transaction) {
                return {
                    success: false,
                    error: `Transaction ${transactionId} not found`
                };
            }

            await transaction.rollback();
            this.transactions.delete(transactionId);

            return {
                success: true
            };
        } catch (error) {
            return {
                success: false,
                error: (error as Error).message
            };
        }
    }

    /**
     * 执行查询
     * @param tableName 表名
     * @param conditions 查询条件
     */
    async query(tableName: string, conditions?: QueryCondition[]): Promise<OperationResult> {
        try {
            await this.initialize();

            const table = this.tableInstances.get(tableName);
            if (!table) {
                return {
                    success: false,
                    error: `Table ${tableName} not found`
                };
            }

            return await table.find(conditions);
        } catch (error) {
            return {
                success: false,
                error: (error as Error).message
            };
        }
    }

    /**
     * 关闭数据库
     */
    async close(): Promise<void> {
        // 回滚所有未完成的事务
        for (const [transactionId, transaction] of this.transactions) {
            try {
                await transaction.rollback();
            } catch (error) {
                console.error(`Failed to rollback transaction ${transactionId}:`, error);
            }
        }

        // 清理资源
        this.tables.clear();
        this.tableInstances.clear();
        this.transactions.clear();
        this.initialized = false;
    }
}
